#include <iostream>
#include <unistd.h>
#include <string>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <sys/types.h>
#include "task.hpp"
using namespace std;

enum
{
    UsageError = 1,
    ArgError, // 参数错误
    PipeError
};

void Usage(const char *str)
{
    printf("Usage:%s sub_process_num\n", str);
}

class Channel
{
public:
    Channel(int wfd, int sub_process_id, const string &name)
    {
        _wfd = wfd;
        _sub_process_id = sub_process_id;
        _name = name;
    }
    void Debug()
    {
        cout << "wfd:" << _wfd << ",sub_process_id:" << _sub_process_id << ",name:" << _name << endl;
    }
    int wfd()
    {
        return _wfd;
    }
    string name()
    {
        return _name;
    }
    int pid()
    {
        return _sub_process_id;
    }

private:
    int _wfd;            // 父进程的具体的写端(父进程具有多个写端)
    int _sub_process_id; // 管道中获取数据的子进程pid(存在多个子进程)
    string _name;        // 管道编号
};

class ProcessPool
{
public:
    ProcessPool(int sub_process_num)
    {
        _sub_process_num = sub_process_num;
    }
    int CreatProcess(work_t work)
    {
        for (int i = 0; i < _sub_process_num; i++)
        {
            int pipefd[2] = {0, 0};
            int n = pipe(pipefd);
            if (n < 0)
            {
                return PipeError;
            }

            pid_t id = fork();
            if (id == 0)
            {
                // child
                close(pipefd[1]);

                // 获取任务时可以从stdin中获取任务,stdin->_fileno=0;
                dup2(pipefd[0], 0);

                // execute task
                work();
                exit(0);
            }
            close(pipefd[0]);
            string channelname = "channel-" + to_string(i);
            channels.push_back(Channel(pipefd[1], id, channelname));
        }
        return 0;
    }
    int NextChannel()
    {
        static int next = 0;
        int channel = next;
        next++;
        next %= channels.size();
        return channel; // 轮询式确定信道,负载均衡
    }
    void Debug()
    {
        for (auto &e : channels)
        {
            e.Debug();
        }
    }

    void SendTaskCode(int channel,int command_code)
    {
        cout << "send code: " << command_code << " to " << channels[channel].name() <<
         " sub prorcess id: " <<  channels[channel].pid() << endl;
        write(channels[channel].wfd(),&command_code,sizeof(command_code));
        sleep(1);
    }

private:
    vector<Channel> channels;
    int _sub_process_num;
};

int NextTask()
{
    return rand() % 4;
}
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        return UsageError;
    }
    int sub_process_num = atoi(argv[1]);
    if (sub_process_num <= 0)
    {
        return ArgError;
    }
    srand((uint32_t)time(nullptr));
    // 创建进程与信道
    ProcessPool *processpool_ptr = new ProcessPool(sub_process_num);
    processpool_ptr->CreatProcess(worker);
    processpool_ptr->Debug();

    // 控制子进程
    // 1.父进程负载均衡式选择管道(哪一个子进程执行任务)
    // 2.父进程随机选择任务(创建多个任务)
    // 3.父进程发送任务
    // 4.子进程执行任务(回调函数机制实现)

    while (true)
    {
        // 选择管道
        int channel = processpool_ptr->NextChannel();
        // 随机选择任务(父进程随机分配任务码,子进程执行任务码所对应的函数指针数组下标存放的任务)
        int command_code=NextTask();
        //父进程发送任务
        processpool_ptr->SendTaskCode(channel,command_code);
        sleep(1);
    }
    sleep(100);
    // 回收子进程

    return 0;
}